package com.sukaiyi.generator.ui;

import com.sukaiyi.generator.config.model.StructTemplate;
import com.sukaiyi.generator.config.model.TplType;
import com.sukaiyi.generator.ui.renderer.CloseTabAction;
import com.sukaiyi.generator.utils.IdeaUIUtils;
import com.sukaiyi.generator.utils.StringUtils;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.ui.EditorTextField;
import com.intellij.ui.JBSplitter;
import com.intellij.ui.tabs.TabInfo;
import com.intellij.ui.tabs.impl.JBTabsImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class GeneratedCodePreviewer extends JPanel implements TreeSelectionListener, TreeNodeDeleteListener {

    private JPanel rootPanel;
    private JBSplitter splitter;
    private JBTabsImpl jbTabs;
    private TemplateTree tree;

    private StructTemplate template;
    private Project project;

    public GeneratedCodePreviewer(Project project, StructTemplate template) {
        this.template = template;
        this.project = project;
        setLayout(new BorderLayout());
        add(rootPanel);
        tree = new TemplateTree();
        jbTabs = new JBTabsImpl(project);
        splitter.setFirstComponent(tree.get());
        splitter.setSecondComponent(jbTabs);
        splitter.setProportion(0.2f);
        setStructTemplate(template);
        tree.addTreeSelectionListener(this);
        tree.addTreeNodeDeleteListener(this);
    }

    public void setStructTemplate(StructTemplate template) {
        tree.removeAll();
        jbTabs.removeAllTabs();
        this.template = template;
        if (template != null) {
            tree.setStructTemplate(template);
        }
    }

    private void createUIComponents() {
        splitter = new JBSplitter();
    }

    public StructTemplate getEditedStructTemplate() {
        StructTemplate template = tree.getStructTemplate();
        Queue<StructTemplate> queue = new LinkedList<>();
        queue.offer(template);
        while (!queue.isEmpty()) {
            StructTemplate tpl = queue.poll();
            if (tpl.getType() == TplType.TEMPLATE) {
                TabInfo tabInfo = jbTabs.findInfo(tpl);
                if (tabInfo != null) {
                    EditorTextField editor = (EditorTextField) tabInfo.getComponent();
                    tpl.setContent(editor.getText());
                }
            } else {
                List<StructTemplate> children = tpl.getChildren();
                if (children != null && children.size() > 0) {
                    queue.addAll(children);
                }
            }
        }
        return template;
    }

    @Override
    public void valueChanged(TreeSelectionEvent e) {
        TreePath path = e.getNewLeadSelectionPath();
        if (path == null) {
            return;
        }
        DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) path.getLastPathComponent();
        StructTemplate template = (StructTemplate) treeNode.getUserObject();
        if (template.getType() == TplType.TEMPLATE) {
            TabInfo tabInfo = jbTabs.findInfo(template);
            if (tabInfo != null) {
                jbTabs.select(tabInfo, false);
                return;
            }
            String suffix = StringUtils.getFileSuffix(template.getName());
            FileType fileType = IdeaUIUtils.getFileTypeByFileSuffix(suffix);
            EditorTextField editor = IdeaUIUtils.createEditorTextField(project, fileType);
            Document document = EditorFactory.getInstance().createDocument(template.getContent());
            editor.setDocument(document);
            editor.setCaretPosition(0);
            tabInfo = new TabInfo(editor);
            tabInfo.setObject(template);
            tabInfo.setText(template.getName());
            tabInfo.setIcon(IdeaUIUtils.getIconByFileSuffix(suffix));
            TabInfo finalTabInfo = tabInfo;
            tabInfo.setTabLabelActions(new ActionGroup() {
                @NotNull
                @Override
                public AnAction[] getChildren(@Nullable AnActionEvent e) {
                    return new AnAction[]{new CloseTabAction() {
                        @Override
                        public void actionPerformed(@NotNull AnActionEvent e) {
                            EditorTextField editor = (EditorTextField) finalTabInfo.getComponent();
                            StructTemplate tpl = (StructTemplate) finalTabInfo.getObject();
                            tpl.setContent(editor.getText());
                            jbTabs.removeTab(finalTabInfo);
                        }
                    }};
                }
            }, ActionPlaces.EDITOR_TAB);
            jbTabs.addTab(tabInfo);
            jbTabs.setTabDraggingEnabled(true);
            jbTabs.select(tabInfo, false);
            jbTabs.getPresentation().setPaintBlocked(false, true);
        }
    }

    @Override
    public void onDelete(MutableTreeNode[] treeNodes) {
        for (MutableTreeNode treeNode : treeNodes) {
            StructTemplate template = (StructTemplate) ((DefaultMutableTreeNode) treeNode).getUserObject();
            if (template == null || template.getType() == TplType.MODULE) {
                continue;
            }
            List<TabInfo> tabs = jbTabs.getTabs();
            for (TabInfo tab : tabs) {
                StructTemplate tpl = (StructTemplate) tab.getObject();
                if (tpl == template) {
                    jbTabs.removeTab(tab);
                }
            }
        }
    }
}
